#include<stdio.h>
#include<assert.h>
#include<string.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<sys/stat.h>
#include <fcntl.h>
#include<errno.h>

#define MAX 1024
#define ARGC 24
#define SEP " "

enum redir
{
  REDIR_INPUT = 0,
  REDIR_OUTPUT,
  REDIR_ADDEND,
  REDIR_NONE
};

void CheckRedir(char* argv[],enum redir* redir_type)
{
  //char* arg = (char*)'\0';
  for(int i = 0; argv[i]; ++i)
  {
    if(strcmp(argv[i],">") == 0)
    {
      *redir_type = REDIR_OUTPUT;
      argv[i] = NULL;
      break;
    }
    else if(strcmp(argv[i],"<") == 0)
    {
      *redir_type = REDIR_INPUT;
      argv[i] = NULL;
      break;
    }
    else if(strcmp(argv[i],">>") == 0)
    {
      *redir_type = REDIR_ADDEND;
      argv[i] = NULL;
      break;
    }
  }
}

int split(char* command,char* argv[])
{
  assert(command);
  assert(argv);
  argv[0] = strtok(command,SEP);
  if(argv[0] == NULL)
  {
    return -1;
  }
  int i = 1;
  while((argv[i++] = strtok(NULL,SEP)));
  return 0;
}
//void DebugPrint(char* argv[],char* LOG)
void DebugPrint(char* argv[])
{
  int i = 0;
  while(argv[i] != NULL)
  {
    printf("%s\n",argv[i++]);
  }
  //printf("%s\n",LOG);
}
void ShowEnv()
{
  extern char** environ;
  for(int i = 0; environ[i]; ++i)
  {
    printf("%d:%s\n",i,environ[i]);
  }
}
int main()
{
  char myenv[24][1024];
  int env_index = 0;
  int last_exit = 0;
  while(1)
  {
    enum redir redir_type = REDIR_NONE;
    (void)redir_type;
    printf("[zrb@mychine currpath]# ");
    fflush(stdout);
    char command[MAX] = {0};
    char* argv[ARGC] = {0};
    char* s = fgets(command,sizeof(command),stdin);
    command[strlen(command)-1] = '\0';
    assert(s);
    (void)s;
    int n = split(command,argv);
    if(n != 0) continue;
    //DebugPrint(argv);
    if(strcmp(argv[0],"cd") == 0)
    {
      if(argv[1] != NULL) chdir(argv[1]);
      continue;
    }
    else if(strcmp(argv[0],"env") == 0)
    {
      ShowEnv();
      continue;
    }
    else if(strcmp(argv[0],"export") == 0)
    {
      if(argv[1] != NULL)
      {
        strcpy(myenv[env_index],argv[1]);
        putenv(myenv[env_index++]);
      }
      continue;
    }
    else if(strcmp(argv[0],"echo") == 0)
    {
      const char* targe_env = NULL;
      if(argv[1][0] == '$')
      {
        if(argv[1][1] == '?')
        {
          printf("%d\n",last_exit);
        }
        else
        {
          targe_env = getenv(argv[1]+1);
          if(targe_env) printf("%s:%s\n",argv[1]+1,targe_env);
        }
        continue;
      }
    }
    else if(strcmp(argv[0],"ls") == 0)
    {
      int pos = 0;
      while(argv[pos]) pos++;
      argv[pos++] = (char*)"--color=auto";
      argv[pos] = NULL;
    }
    else if(strcmp(argv[0],"ll") == 0)
    {
      char* str = (char*)"ls";
      char* strr = (char*)"-l";
      char* strrr = (char*)"--color=auto";
      argv[0] =str;
      argv[1] = strr;
      argv[2] = strrr; 
    }
    pid_t id = fork();
    assert(id >= 0);
    (void)id;
    if(id == 0)
    {
      CheckRedir(argv,&redir_type);
      if(redir_type != REDIR_NONE)
      {
        int i = 0;
        while(argv[i] != NULL) ++i;
        ++i;
        char* LOG = argv[i];
        //DebugPrint(argv);
        if(redir_type == REDIR_INPUT)//wc -l test.txt 和 wc -l < test.txt 进行检验
        {
          int fd = open(LOG,O_RDONLY);
          //printf("%d\n",fd);
          dup2(fd,0);
        }
        else if(redir_type == REDIR_OUTPUT)
        {
          int fd = open(LOG,O_WRONLY | O_CREAT | O_TRUNC,0666);//echo 100 > test.txt进行检验
          //printf("%d\n",fd);
          //prindtf("%s\n",strerror(errno));
          dup2(fd,1);
        }
        else if(redir_type == REDIR_ADDEND)//追加重定向(文件描述符是0，相比输入重定向是不清空文件)，注意不要写成错误重定向(文件描述符号是3)
        {
          int fd = open(LOG,O_WRONLY | O_APPEND);//echo 1000 >> test.txt进行检验
          //prindtf("%d\n",fd);
          dup2(fd,1);
        }
      }
      execvp(argv[0],argv);
      exit(1);
    }
    int status = 0;
    pid_t ret = waitpid(id,&status,0);
    if(ret > 0)
    {
      last_exit = WEXITSTATUS(status);
    }
  }   
}
